Ruby 日記 16日目: Enumerator.new と Enumerator::Yielder
次のプログラムの__(1)__に適切な内容を選択して実行すると、[97, 112, 112, 108, 101]と表示されます。
期待した結果を得られるように正しい選択肢を選んでください。
code:gold/ex16/main.rb
enum_char = Enumerator.new do |yielder|
"apple".each_char do |chr|
__(1)__
end
end
array = enum_char.map do |chr|
chr.ord
end
p array
選択肢:
yielder.call chr
yielder(chr)
yielder << chr
yielder.inject chr
解説:
new(size=nil) {|y| ... } -> Enumerator
Enumerator オブジェクトを生成して返します。与えられたブロックは Enumerator::Yielder オブジェクトを 引数として実行されます。
メソッドはインスタンスメソッド <<, to_proc, yield の3つ
ぜんぶ Enumerator.new で使うメソッドです。 て書いてあるね
生成された Enumerator オブジェクトに対して each を呼ぶと、この生成時に指定されたブロックを 実行し、Yielder オブジェクトに対して << メソッドが呼ばれるたびに、 each に渡されたブロックが繰り返されます。
Yielder オブジェクトに対して << メソッドが呼ばれるたび なるほど〜
じゃあ << があるかないかが重要なのか
new に渡されたブロックが終了した時点で each の繰り返しが終わります。 このときのブロックの返り値が each の返り値となります。
code:sh
# ruby gold/ex16/choice01.rb
from gold/ex16/choice01.rb:2:in `each_char'
from gold/ex16/choice01.rb:2:in `block in <main>'
from gold/ex16/choice01.rb:7:in `each'
from gold/ex16/choice01.rb:7:in `each'
from gold/ex16/choice01.rb:7:in `map'
from gold/ex16/choice01.rb:7:in `<main>'
code:sh
# ruby gold/ex16/choice02.rb
gold/ex16/choice02.rb:3:in block (2 levels) in <main>': undefined method yielder' for main:Object (NoMethodError)
from gold/ex16/choice02.rb:2:in `each_char'
from gold/ex16/choice02.rb:2:in `block in <main>'
from gold/ex16/choice02.rb:7:in `each'
from gold/ex16/choice02.rb:7:in `each'
from gold/ex16/choice02.rb:7:in `map'
from gold/ex16/choice02.rb:7:in `<main>'
code:sh
# ruby gold/ex16/choice03.rb
code:sh
# ruby gold/ex16/choice04.rb
from gold/ex16/choice04.rb:2:in `each_char'
from gold/ex16/choice04.rb:2:in `block in <main>'
from gold/ex16/choice04.rb:7:in `each'
from gold/ex16/choice04.rb:7:in `each'
from gold/ex16/choice04.rb:7:in `map'
from gold/ex16/choice04.rb:7:in `<main>'
yielder.inject なんて存在しないのか〜。yielder << chrとyielder.inject の2つが正解だと思っちゃった。
メソッドはインスタンスメソッド <<, to_proc, yield の3つ
これよく覚えておこう
正解は「yielder << chr」だね
/icons/hr.icon
生成された Enumerator オブジェクトの each メソッドを呼ぶと Enumerator::Yielder オブジェクトが渡されたブロックが実行され、ブロック内の << が呼ばれるたびに each に渡されたブロックが << に渡された値とともに繰り返されます。
code:rb
enum = Enumerator.new do |y|
y << 1
y << 2
y << 3
end
enum.each do |v|
p v
end
# => 1
# 2
# 3
引数を Enumerator::Yielder#yield に渡す Proc を返します。これは Enumerator::Yielder オブジェクトを他のメソッドにブロック引数として直接渡すために使えます。
code:rb
text = <<-END
Hello
こんにちは
END
enum = Enumerator.new do |y|
text.each_line(&y)
end
enum.each do |line|
p line
end
# => "Hello\n"
# "こんにちは\n"
生成された Enumerator オブジェクトの each メソッドを呼ぶと Enumerator::Yielder オブジェクトが渡されたブロックが実行され、ブロック内の yield メソッドが呼ばれるたびに each に渡されたブロックが yield メソッドに渡された値とともに繰り返されます。
code:rb
enum = Enumerator.new do |y|
y.yield 1, 2, 3
end
enum.each do |x, y, z|
end